package com.ruoyi.system.utils;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.config.FtpConfig;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.FileObject;
import com.ruoyi.common.enums.comlbs.*;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.file.FtpUtil;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.tree.VideoTree;
import com.ruoyi.system.domain.vo.common.DeviceGps;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.math.NumberUtils;

import java.io.File;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 描述 1077项目通用工具类
 * 作者 ZhangPing
 * 创建时间 2023/8/16 16:16
 */
public class ComLbsUtils {

    /**
     * 大数据GPS定位数据转换
     * @param item
     * @return
     */
    public static DeviceGps bigDataGpsFormat(JSONObject item){
        JSONObject popJson = item.getJSONObject("pop");
//        JSONObject poiJson = item.getJSONObject("poi");
        DeviceGps deviceGps = new DeviceGps()
                .setGdt(DateUtils.formatTimestamp(item.getLong("gte")/1000))
                .setDre(item.getIntValue("dre"))
                .setDvo(item.getString("dvo"))
                .setGte(item.getLong("gte"))
                .setMie(item.getIntValue("totalMile", 0))
                .setKilometer(item.getIntValue("totalMile", 0)/1000.0)
//                .setDayKMeter(item.getDouble("dayKMeter"))
                .setDistance(item.getIntValue("distance"))
                .setLat(item.getDouble("lat"))
                .setLng(item.getDouble("lng"))
                .setSpd(item.getIntValue("spd", 0))
                .setSatelliteCount(popJson == null ? item.getIntValue("satelliteCount", 0) : popJson.getIntValue(PopMapEnum.SatelliteCount.getCode().toString()))
                .setLocation(item.getString("address"))
                .setSts(item.getList("sts", Integer.class));
//                .setAlm(item.getList("alm", Integer.class))
//                .setPop(popJson);


        return deviceGps;
    }

    /**
     * 根据大数据返回的设备Map获取车辆在线状态
     * @param device
     * @return
     */
    public static VehicleStatusEnum getVehicleStatus(DeviceGps device){
        if (device == null || device.getGte() == null) return VehicleStatusEnum.NOT_LOCATE;
        // 状态
        List<Integer> stsList = device.getSts();
        // 速度
        int spd = device.getSpd();
        // 5分钟内在线
        if (System.currentTimeMillis() - device.getGte() < VehicleStatusEnum.offlineTime) {
            if (!stsList.contains(StsListEnum.Located.getCode())) {
                //定位失败
                return VehicleStatusEnum.POSITIONING_FAIL;
            } else {
                //已定位
                if (stsList.contains(StsListEnum.Acc.getCode())) {
                    if (spd > 0) {
                        return VehicleStatusEnum.DRIVING;
                    } else {
                        return VehicleStatusEnum.STOP;
                    }
                } else {
                    return VehicleStatusEnum.FLAME_OUT;
                }
            }
        } else {
            return VehicleStatusEnum.OFFLINE;
        }
    }

    /**
     * 根据大数据返回的设备Map获取监管对象在线状态
     * @param device
     * @return
     */
    public static VehicleStatusEnum getObjectStatus(DeviceGps device, Integer objType){
        if (objType == null) objType = 0;
        if (device == null) return VehicleStatusEnum.NOT_LOCATE;
        // 状态
        List<Integer> stsList = device.getSts();
        // 速度
        int spd = device.getSpd();
        // 5分钟内在线
        if (System.currentTimeMillis() - device.getGte() < VehicleStatusEnum.offlineTime) {
            if (!stsList.contains(StsListEnum.Located.getCode())) {
                //定位失败
                return VehicleStatusEnum.POSITIONING_FAIL;
            } else {  //已定位
                if (ObjectTypeEnum.VEHICLE.getCode() == objType || ObjectTypeEnum.SHIP.getCode() == objType) {
                    //车辆、船
                    if (stsList.contains(StsListEnum.Acc.getCode())) {
                        if (spd > 0) {
                            return VehicleStatusEnum.DRIVING;
                        } else {
                            return VehicleStatusEnum.STOP;
                        }
                    } else {
                        return VehicleStatusEnum.FLAME_OUT;
                    }
                } else {
                    //人员、物品、牲畜、其他
                    return VehicleStatusEnum.ONLINE;
                }
            }
        } else {
            return VehicleStatusEnum.OFFLINE;
        }
    }

    /**
     * 递归统计树节点的车辆数、有视频车辆数的
     */
    public static VideoTree treeVehicleCount(VideoTree tree, boolean onlyOnline) {
        //没有子节点或者节点类型不为人、车
        if (tree.getChildren().isEmpty() || tree.getType() == OrgTypeEnum.DEVICE.getCode()) return tree;
        //有子节点,往下找
        Iterator<VideoTree> it = tree.getChildren().iterator();
        while (it.hasNext()) {
            VideoTree child = it.next();
            if (child.getType() == OrgTypeEnum.DEVICE.getCode()) {
                // 统计车辆总数
                tree.setTotalCount(tree.getTotalCount() + 1);
                if (VehicleStatusEnum.DRIVING.getCode() == child.getStatus()
                        || VehicleStatusEnum.STOP.getCode() == child.getStatus()
                        || VehicleStatusEnum.POSITIONING_FAIL.getCode() == child.getStatus()) {
                    // 统计有视频的车辆
                    tree.setHasVideoCount(tree.getHasVideoCount() + 1);
                } else if (onlyOnline){
                    it.remove();
                }
            } else {
                VideoTree bean = treeVehicleCount(child, onlyOnline);
                //部门节点车辆数为0，则删除
                if (bean.getType() == OrgTypeEnum.DEVICE.getCode() && bean.getChildren().isEmpty()) {
                    if (onlyOnline) it.remove();
                    continue;
                }
                tree.setHasVideoCount(tree.getHasVideoCount() + bean.getHasVideoCount());
                tree.setTotalCount(tree.getTotalCount() + bean.getTotalCount());//统计车辆树
            }
        }
        return tree;
    }

    /**
     * SIM卡号合法性校验
     * @param simId
     * @return
     */
    public static boolean simIdCheck(String simId){
        String pattern = "^[0-9A-Z]+$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(simId);
        return m.matches();
    }

    /**
     * 用户名合法性校验
     * @param simId
     * @return
     */
    public static boolean userNameCheck(String simId){
        String pattern = "^[a-zA-Z][a-zA-Z0-9_]{1,15}$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(simId);
        return m.matches();
    }

    /**
     * 密码合法性校验
     * @param simId
     * @return
     */
    public static boolean passwordCheck(String simId){
        String pattern = "^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[#?@!$%^&*-]).{8,}$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(simId);
        return m.matches();
    }

    /**
     * 四舍五入
     * @param number
     * @param scale
     * @return
     */
    public static Double round45(Object number, int scale){
        try {
            if (number == null) return 0.0;
            if (number instanceof String) return NumberUtils.toScaledBigDecimal((String) number, scale, RoundingMode.HALF_UP).doubleValue();
            if (number instanceof Double) return NumberUtils.toScaledBigDecimal((Double) number, scale, RoundingMode.HALF_UP).doubleValue();
            if (number instanceof Float) return NumberUtils.toScaledBigDecimal((Float) number, scale, RoundingMode.HALF_UP).doubleValue();
            if (number instanceof Integer) return ((Integer) number).doubleValue();
        } catch (Exception e) {}
        return 0.0;
    }
    public static Double round45(Object number){
        return round45(number, 2);
    }

    /**
     * 直接截取
     * @param number
     * @param scale
     * @return
     */
    public static Double roundDown(Object number, int scale){
        if (number == null) return 0.0;
        if (number instanceof String) return NumberUtils.toScaledBigDecimal((String) number, scale, RoundingMode.DOWN).doubleValue();
        if (number instanceof Double) return NumberUtils.toScaledBigDecimal((Double) number, scale, RoundingMode.DOWN).doubleValue();
        if (number instanceof Float) return NumberUtils.toScaledBigDecimal((Float) number, scale, RoundingMode.DOWN).doubleValue();
        if (number instanceof Integer) return ((Integer) number).doubleValue();
        return 0.0;
    }
    public static Double roundDown(Object number){
        return roundDown(number, 2);
    }

    /**
     * 对象更新时的图片处理，删除多余的文件
     * @param oldFileList
     * @param newFileList
     */
    public static void fileHandle(List<FileObject> oldFileList, List<FileObject> newFileList, boolean isFtp){
        if (ObjectUtils.isEmpty(oldFileList)) return;
        List<String> oldFilePathList = oldFileList.stream().map(FileObject::getPath).collect(Collectors.toList());
        List<String> newFilePathList = ObjectUtils.isEmpty(newFileList) ? new ArrayList<>() : newFileList.stream().map(FileObject::getPath).collect(Collectors.toList());
        List<String> needDeleteFileList = oldFilePathList.stream().filter(i -> !newFilePathList.contains(i)).collect(Collectors.toList());
        deleteFile(needDeleteFileList, isFtp);
    }

    /**
     * 对象更新时出现异常的图片处理，删除新增的文件
     * @param oldFileList
     * @param newFileList
     */
    public static void exceptionFileHandle(List<FileObject> oldFileList, List<FileObject> newFileList, boolean isFtp){
        if (ObjectUtils.isEmpty(newFileList)) return;
        List<String> oldFilePathList = ObjectUtils.isEmpty(oldFileList) ? new ArrayList<>() : oldFileList.stream().map(FileObject::getPath).collect(Collectors.toList());
        List<String> newFilePathList = newFileList.stream().map(FileObject::getPath).collect(Collectors.toList());
        List<String> needDeleteFileList = newFilePathList.stream().filter(i -> !oldFilePathList.contains(i)).collect(Collectors.toList());
        deleteFile(needDeleteFileList, isFtp);
    }

    /**
     * 删除文件
     * @param fileList
     * @param isFtp
     */
    public static void deleteFile(List<String> fileList, boolean isFtp){
        if (ObjectUtils.isEmpty(fileList)) return;
        if (isFtp){
            //FTP文件删除
            FtpConfig ftpConfig = SpringUtils.getBean(FtpConfig.class);
            FtpUtil ftpUtil = SpringUtils.getBean(FtpUtil.class);
            fileList.stream().forEach(path -> {
                ftpUtil.deleteFile(ftpConfig.getPrefixPath() + path);
            });
        }else {
            //服务器文件删除
            fileList.stream().forEach(path -> {
                File file = new File(path.replace(Constants.RESOURCE_PREFIX, RuoYiConfig.getProfile()));
                if (file.exists()) file.delete();
            });
        }
    }
}
